`include "ysyx_23060189_cpu.svh"
`include "ysyx_23060189_isa.svh"

module ysyx_23060189_Alu(
  input  wire [`ysyx_23060189_DataBus]   imm,
  input  wire [`ysyx_23060189_DataBus]   rs1_data,
  input  wire [`ysyx_23060189_DataBus]   rs2_data,
  input  wire [`ysyx_23060189_AddrBus]   pc_out,
  input  wire [`ysyx_23060189_AluOpBus]  Alu_op,
  input  wire [`ysyx_23060189_AluSelBus] A_sel,
  input  wire [`ysyx_23060189_AluSelBus] B_sel,
  output wire [`ysyx_23060189_DataBus]   Alu_out
);

  wire [`ysyx_23060189_DataBus] A;
  wire [`ysyx_23060189_DataBus] B;
  wire [`ysyx_23060189_IsaShamtBus] shamt;

  assign shamt = B[`ysyx_23060189_IsaShamtOps];

  MuxKey #(2, `ysyx_23060189_ALU_SEL_W, 32) MuxA (A, A_sel, {
    `ysyx_23060189_ALU_SEL_R,  rs1_data,
    `ysyx_23060189_ALU_SEL_PC, pc_out
  });

  MuxKey #(2, `ysyx_23060189_ALU_SEL_W, 32) MuxB (B, B_sel, {
    `ysyx_23060189_ALU_SEL_R, rs2_data,
    `ysyx_23060189_ALU_SEL_I, imm
  });

  MuxKey #(12, `ysyx_23060189_ALU_OP_W, 32) Mux (Alu_out, Alu_op, {
    `ysyx_23060189_ALU_ADD,  A + B ,
    `ysyx_23060189_ALU_CP_A, A,
    `ysyx_23060189_ALU_CP_B, B,
    `ysyx_23060189_ALU_SLTU, {31'b0, A < B ? 1'b1 : 1'b0},
    `ysyx_23060189_ALU_SUB,  A - B,
    `ysyx_23060189_ALU_XOR,  A ^ B,
    `ysyx_23060189_ALU_SRA,  $signed(A) >>> shamt,
    `ysyx_23060189_ALU_AND,  A & B,
    `ysyx_23060189_ALU_SL,   A << shamt,
    `ysyx_23060189_ALU_OR,   A | B,
    `ysyx_23060189_ALU_SRL,  A >> shamt,
    `ysyx_23060189_ALU_SLT,  {31'b0, $signed(A) < $signed(B) ? 1'b1 : 1'b0}
  });

endmodule
